package com.ht.api.db.request;

import java.util.Set;

import org.reflections.Reflections;

import com.ht.api.db.Db;
import com.ht.api.db.DbList;
import com.ht.api.db.Entity;
import com.ht.api.db.annotate.FuncAdd;
import com.ht.api.db.annotate.FuncBatch;
import com.ht.api.db.annotate.FuncCall;
import com.ht.api.db.annotate.FuncDel;
import com.ht.api.db.annotate.FuncEdit;
import com.ht.api.db.annotate.FuncGroup;
import com.ht.api.db.annotate.FuncId;
import com.ht.api.db.annotate.FuncName;
import com.ht.api.db.annotate.FuncParam;
import com.ht.api.db.annotate.FuncParams;
import com.ht.api.db.annotate.FuncQuery;
import com.ht.api.db.enums.Param;
import com.ht.api.db.exception.HtException;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 请求处理接口的helper
 */
@Slf4j
public class HandleRequestHelper {
	/**
	 * 加载所有专用接口到内存中，并返回接口列表
	 */
	public static void loadFunction() {
		log.info("[init]专用接口扫描加载开始...");
		int count = 0;
        try {
        	DbList list = DbList.create();
        	
            // 创建Reflections对象
            Reflections reflections = new Reflections("com.ht");
            
            // 获取包下面的所有有@FuncName注解的类
            Set<Class<?>> interfaces = reflections.getTypesAnnotatedWith(FuncName.class);
            for (Class<?> implClass : interfaces) {
                try {
                	count++;
                    
                    // 根据注解值获取数据库表对象
                	if (!"DemoCall".equals(implClass.getSimpleName()) 
                			&& !"DemoCommonCall".equals(implClass.getSimpleName())) {
                		list.add(saveOrUpdateCall(list, implClass));
                	}
                } catch (Exception e) {
                    log.error("[init]加载专用接口失败: {}, 错误: {}", implClass.getName(), e.getMessage(), e);
                }
            }
            
            // 批量写入数据库
            Db.insertBatchWithStream(list);
        } catch (Exception e) {
            log.error("[init]专用接口扫描加载失败: {}", e.getMessage(), e);
        }
		log.info("[init]专用接口扫描加载结束，共加载{}个接口", count);
	}

	/**
	 * 获取专用接口的参数
	 * @param funcParams
	 * @return
	 */
	public static JSONObject getFuncParam(FuncParams funcParams) {
		JSONObject param = JSONUtil.createObj();
        if (funcParams != null) {
        	for (FuncParam funcParam : funcParams.value()) {
        		if (funcParam.type() == Param.VALUE) {
        			param.set(funcParam.code(), funcParam.value());
        		} else if (funcParam.type() == Param.OBJ) {
        			String value = funcParam.value();
        			value = StrUtil.isBlank(value) ? "{}" : value;
					param.set(funcParam.code(), JSONUtil.parse(value));
        		} else  if (funcParam.type() == Param.ARRAY){
        			String value = funcParam.value();
        			value = StrUtil.isBlank(value) ? "[]" : value;
        			param.set(funcParam.code(), JSONUtil.parseArray(value));
        		}
			}
        }
		return JSONUtil.createObj().set("param", param);
	}

	/**
	 * 根据专用接口的注解，同步维护数据库
	 * @param list call表数据集合
	 * @param implClass 接口类class对象
	 */
	 public static Entity saveOrUpdateCall(DbList list, Class<?> implClass) {
        // 提取各个注解值
		FuncId funcId = implClass.getAnnotation(FuncId.class);
    	FuncName funcName = implClass.getAnnotation(FuncName.class);
    	FuncGroup funcGroup = implClass.getAnnotation(FuncGroup.class);
        FuncParams funcParams = implClass.getAnnotation(FuncParams.class);
        String path = implClass.getName();
        String key = implClass.getSimpleName();
        
        // 验证必须有的注解
        if (funcId == null) {
        	throw new HtException("接口类" + path + "缺少@FuncId注解~");
        }
        if (StrUtil.isBlank(funcId.value())) {
        	throw new HtException("接口类" + path + "@FuncId注解值不能为空~");
        }
        if (funcName == null) {
        	throw new HtException("接口类" + path + "缺少@FuncName注解~");
        }
        if (StrUtil.isBlank(funcName.value())) {
        	throw new HtException("接口类" + path + "@FuncName注解值不能为空~");
        }
        
        // 验证funcId和funcKey是否重复
        if (list != null) {
	        for (Entity entity : list) {
				if (funcId.value().equals(entity.getStr("main_id"))) {
					throw new HtException("接口类" + path + "的@FuncId与另一个接口重复，请仔细检查~");
				}
			}
	        for (Entity entity : list) {
	        	if (key.equals(entity.getStr("key"))) {
	        		throw new HtException("接口类" + path + "的类名与另一个接口重复，请仔细检查~");
	        	}
	        }
        }
        
        // 查询groupId，如果没有找到，则自动创建一个
        String groupId = null;
        if (funcGroup != null && StrUtil.isNotBlank(funcGroup.value())) {
        	groupId = Db.createSqlParser("sys_group").select("main_id")
        			.where("group_code", "call")
        			.where("group_name", funcGroup.value()).val(String.class);
        	if (groupId == null) {
        		Entity sysGroup = Db.createEntity("sys_group");
        		sysGroup.set("group_name", funcGroup.value());
        		sysGroup.set("group_code", "call");
        		Db.insert(sysGroup);
        		groupId = sysGroup.getMainId();
        	}
        }
        
        // 构造表数据返回
        Entity call = Entity.create("call");
        call.set("main_id", funcId.value());
        call.set("name", funcName.value());
        call.set("config", getConfig(implClass));
        call.set("key", key);
        call.set("param", getFuncParam(funcParams));
    	call.set("group_id", groupId);
    	call.set("type", 1);
    	call.set("package", path);
    	
    	return call; 
	}

	/**
	 * 根据注解获取接口配置json
	 * @param implClass 接口类
	 * @return
	 */
	private static JSONObject getConfig(Class<?> implClass) {
        FuncAdd funcAdd = implClass.getAnnotation(FuncAdd.class);
        FuncEdit funcEdit = implClass.getAnnotation(FuncEdit.class);
        FuncDel funcDel = implClass.getAnnotation(FuncDel.class);
        FuncQuery funcQuery = implClass.getAnnotation(FuncQuery.class);
        FuncBatch funcBatch = implClass.getAnnotation(FuncBatch.class);
        FuncCall funcCall = implClass.getAnnotation(FuncCall.class);
        
        JSONObject config = JSONUtil.createObj();
        if (funcAdd != null) {
        	config.set("type", "add");
        	config.set("table", funcAdd.value());
        } else if (funcEdit != null) {
        	config.set("type", "edit");
        	config.set("table", funcEdit.value());
        } else if (funcDel != null) {
        	config.set("type", "del");
        	config.set("table", funcDel.value());
        } else if (funcQuery != null) {
        	config.set("type", "query");
        	config.set("table", funcQuery.value());
        } else if (funcBatch != null) {
        	config.set("type", "batch");
        	config.set("table", funcBatch.value());
        } else if (funcCall != null) {
        	config.set("type", "call");
        }
		return config;
	}
}
